﻿using MediatR;
using Microsoft.Extensions.Options;
using Sgr.Application;
using Sgr.Application.Commands;
using Sgr.Generator;
using Sgr.Identity;
using Sgr.Identity.Services;
using Sgr.Indentity.Application.ViewModels;
using System.Security.Claims;

namespace Sgr.Indentity.Application.Commands
{
    public class RefreshTokenCommandHandle :
     IdentityCommandHandleBase,
     IRequestHandler<RefreshTokenCommand, CommandResult<TokenViewModel>>
    {
        private readonly IdentityOptions _identityOptions;
        private readonly ISignatureChecker _signatureChecker;
        private readonly IStringIdGenerator _stringIdGenerator;
        private readonly ITokenBlacklistService _tokenBlacklistService;

        public RefreshTokenCommandHandle(
            IAccountAuthService accountService,
            IHttpContextAccessor httpContextAccessor,
            ISignatureChecker signatureChecker,
            IStringIdGenerator stringIdGenerator,
            ITokenBlacklistService tokenBlacklistService,
            IOptions<IdentityOptions> options)
            : base(accountService, httpContextAccessor)
        {
            _identityOptions = options?.Value ?? throw new ArgumentNullException(nameof(options));
            _signatureChecker = signatureChecker ?? throw new ArgumentNullException(nameof(signatureChecker));
            _stringIdGenerator = stringIdGenerator ?? throw new ArgumentNullException(nameof(stringIdGenerator));
            _tokenBlacklistService = tokenBlacklistService ?? throw new ArgumentNullException(nameof(tokenBlacklistService));
        }

        public async Task<CommandResult<TokenViewModel>> Handle(
            RefreshTokenCommand request,
            CancellationToken cancellationToken)
        {
            // 验证请求参数
            if (!ValidateRequest(request))
                return CommandResult.Invalid<TokenViewModel>("请求参数无效");

            // 获取刷新令牌
            var oldRefreshToken = GetRefreshTokenFromCookie();
            if (string.IsNullOrEmpty(oldRefreshToken))
                return CommandResult.Invalid<TokenViewModel>("刷新令牌验证失败");

            // 验证访问令牌
            var jwtToken = GetJwtTokenFromAccessToken(request.AccessToken ?? "");
            if (jwtToken == null)
            {
                return CommandResult.Invalid<TokenViewModel>("无效的访问令牌");
            }

            var userId = jwtToken.Claims.FirstOrDefault(c => c.Type == Constant.CLAIM_USER_ID)?.Value;
            var loginName = jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
            var dispalyName = jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value ?? "";
            var orgId = jwtToken.Claims.FirstOrDefault(c => c.Type == Constant.CLAIM_USER_ORGID)?.Value;

            if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(loginName) || string.IsNullOrEmpty(orgId))
                return CommandResult.Invalid<TokenViewModel>("访问令牌格式无效");

            // JWT TOKEN 添加至黑名单
            await AddTokenToBlacklistAsync(_tokenBlacklistService, jwtToken, _identityOptions.JWT);

            // 验证并处理刷新令牌
            return await ProcessRefreshTokenAsync(userId, loginName, dispalyName, orgId, oldRefreshToken, cancellationToken);
        }

        private bool ValidateRequest(RefreshTokenCommand request)
        {
            // 基本参数验证
            if (request == null || string.IsNullOrEmpty(request.AccessToken))
            {
                return false;
            }

            // 签名验证
            if (_identityOptions.UseSignature)
            {
                if (string.IsNullOrEmpty(request.Signature) ||
                    string.IsNullOrEmpty(request.Timestamp) ||
                    string.IsNullOrEmpty(request.Nonce))
                {
                    return false;
                }

                if (!_signatureChecker.VerifySignature(
                    request.Signature,
                    request.Timestamp,
                    request.Nonce,
                    request.AccessToken,
                    request.AccessToken))
                {
                    return false;
                }
            }

            return true;
        }

        private string? GetRefreshTokenFromCookie()
        {
            return _httpContextAccessor?.HttpContext?.Request?.Cookies[_identityOptions.JWT?.RefreshTokenCookieName ?? "refreshToken"];
        }

        private async Task<CommandResult<TokenViewModel>> ProcessRefreshTokenAsync(
            string userId,
            string loginName,
            string displayName,
            string orgId,
            string oldRefreshToken,
            CancellationToken cancellationToken)
        {
            // 获取用户信息
            if (string.IsNullOrEmpty(userId))
                return CommandResult.Invalid<TokenViewModel>("无法获取用户标识");

            // 验证刷新令牌
            var (validateResult, account) = await _accountService.ValidateRefreshTokenAsync(
                userId,
                oldRefreshToken,
                cancellationToken);

            if (validateResult != ValidateRefreshTokenResults.Success || account == null)
            {
                string errorMessage = GetValidateErrorMessage(validateResult);
                //if (account == null)
                //    errorMessage += "#无法验证用户身份信息";

                await CreateLoginLogAsync(userId, loginName, displayName, AccountLoginWay.RefreshToken, false, errorMessage, orgId, cancellationToken);
                return CommandResult.Invalid<TokenViewModel>(errorMessage);
            }

            // 生成新的访问令牌和刷新令牌
            var accessToken = await GenerateTokensAsync(account, oldRefreshToken, cancellationToken);

            // 记录成功日志
            await CreateLoginLogAsync(userId, loginName, displayName, AccountLoginWay.RefreshToken, true, string.Empty, orgId, cancellationToken);

            return CommandResult.Success(new TokenViewModel
            {
                AccessToken = accessToken,
                ExpireSeconds = _identityOptions.JWT.ExpireSeconds
            });
        }

        private async Task<string> GenerateTokensAsync(
            Account account,
            string oldRefreshToken,
            CancellationToken cancellationToken)
        {
            // 生成新的访问令牌
            string jti = _stringIdGenerator.GenerateUniqueId();
            var claims = GetClaims(jti, account);
            string accessToken = CreateAccessToken(claims, _identityOptions.JWT);

            // 生成新的刷新令牌
            string newRefreshToken = _stringIdGenerator.GenerateUniqueId();
            await _accountService.CreateRefreshTokenAsync(
                account.Id,
                newRefreshToken,
                oldRefreshToken,
                _identityOptions.JWT.RefreshTokenExpireMinutes,
                _httpContextAccessor?.HttpContext?.GetClientIpAddress() ?? string.Empty,
                cancellationToken);

            // 写入Cookie
            WriteRefreshTokenToCookie(_httpContextAccessor?.HttpContext?.Response, newRefreshToken, _identityOptions.JWT);

            return accessToken;
        }

        private static string GetValidateErrorMessage(ValidateRefreshTokenResults result)
        {
            return result switch
            {
                ValidateRefreshTokenResults.Expire => "刷新令牌已过期",
                ValidateRefreshTokenResults.Frequently => "刷新令牌请求过于频繁",
                ValidateRefreshTokenResults.AccountAbnormal => "账号状态异常",
                ValidateRefreshTokenResults.NotExist => "刷新令牌不存在",
                ValidateRefreshTokenResults.Success => "成功",
                _ => "未知错误",
            };
        }
    }
}